#define _CRT_SECURE_NO_WARNINGS 1

#include"ThreadCache.h"
#include"CentralCache.h"

void* ThreadCache::FetchFromCentralCache(size_t index,size_t alignSize)
{
	//对于需求不同字节大小，分配个数又需要考虑性能，
	// 对于分配8bytes，可以多分配一些（但要有上限），对于256*1024bytes，则少分配些（但要有下限）
	//慢开始反馈调节算法
	//1.最开始不会一次向centralcache一次批量要太多，因为要太多可能用不完
	//2.如果不要这个size大小内存需求，那么betchNum就会不断增长直到上限。
	//3.size越大，一次向centralcache要的batchNum就越小
	//4.size越小，一次向centralcache要的batchNum就越大
	//size_t batchNum = (std::min)(_freeLists[index].MaxSize(), AMSize::NumMoveSize(alignSize));
	size_t batchNum = min(_freeLists[index].MaxSize(), AMSize::NumMoveSize(alignSize));
	if (_freeLists[index].MaxSize() == batchNum)
	{
		//想修改返回值所以使用引用作为MaxSize返回值
		_freeLists[index].MaxSize() += 1;
	}

	void* start = nullptr;
	void* end = nullptr;
	size_t actualNum = CentralCache::GetInstance()->FetchRangeObj(start, end, batchNum, alignSize);
	assert(actualNum >= 1);

	if (actualNum == 1)
	{
		assert(start == end);
		return start;
	}
	else
	{
		//返回1个(start)，剩下的(从start下一个开始)挂接到桶上
		_freeLists[index].PushRange(NextObj(start), end,actualNum-1);
		return start;
	}
}

//申请内存
void* ThreadCache::Allocate(size_t size)
{
	assert(size <= MAX_BYTES);
	size_t alignSize = AMSize::RoundUp(size);
	size_t index = AMSize::Index(size);

	if (!_freeLists[index].Empty())
	{
		return _freeLists[index].Pop();
	}
	else
	{
		//去中心缓存取
		return FetchFromCentralCache(index,alignSize);
	}
}

//释放内存
void ThreadCache::Deallocate(void* ptr, size_t size)
{
	assert(ptr);
	assert(size <= MAX_BYTES);

	//找到映射的自由链表桶，对象插入进去
	size_t index = AMSize::Index(size);
	_freeLists[index].Push(ptr);

	//当链表长度大于一次批量申请的内存时就开始还一段list给CentralCache 
	if (_freeLists[index].Size() >= _freeLists[index].MaxSize())
	{
		ListTooLong(_freeLists[index], size);
	}
}

void ThreadCache::ListTooLong(FreeList& list, size_t size)
{
	void* start = nullptr;
	void* end = nullptr;
	list.PopRange(start, end, list.MaxSize());

	CentralCache::GetInstance()->ReleaseListToSpans(start, size);
}